/**
 * @file ViewAdaptorLsp_interface.h
 * @author Фетисов Михаил Вячеславович (fetisov.michael@yandex.ru)
 * @brief Объявление интерфейса приёма ответов от LSP-сервера.
 * @version 0.1
 * @date 2023-04-14
 *
 * @copyright MIT: Michael Fetisov, Anton Bushev
 *
 */
#ifndef simodo_shell_document_ViewAdaptorLsp_interface_H
#define simodo_shell_document_ViewAdaptorLsp_interface_H

#include "simodo/shell/access/LspStructures.h"

#include <map>

namespace simodo::shell
{

/**
 * @brief Интерфейс получения ответов и нотификаций от языкового сервера.
 *
 * @details
 * Используется при запросе со стороны оболочки через метод ViewAdaptor_interface::getLspInterface.
 *
 * Если плагин документа поддерживает работу с языковым сервером, то ему необходимо
 * реализовать этот интерфейс, чтобы получать ответы и нотификации от языкового сервера.
 * 
 * Часть работы с языковым сервером выполняет оболочка SIMODO edit. Например, она сообщает
 * серверу об открытии документа и передаёт его содержимое. В ответ языковой сервер высылает 
 * нотификацию о диагностике, о чём оболочка сообщает представлению документа, вызывая 
 * метод publishDiagnostics данного интерфейса. 
 * 
 * Остальные методы данного интерфейса будут вызываться оболочкой в случае инициации 
 * команд протокола LSP (Language Server Protocol, см. 
 * https://en.wikipedia.org/wiki/Language_Server_Protocol) через интерфейс 
 * LspAccess_interface, который можно получить через основной интерфейс 
 * оболочки (метод Access_interface::getLspAccess). 
 *
 * @note Оболочка работает с языковым сервером в параллельном потоке, однако
 * все методы данного интерфейса всегда вызываются из главного потока. Для этого
 * используется механизм Qt "сигналы-слоты" внутри самой оболочки. Таким образом, 
 * нет необходимости заботиться о предотвращении "гонки данных".
 */
class ViewAdaptorLsp_interface
{
public:
    virtual ~ViewAdaptorLsp_interface() = default;

    /**
     * @brief Получение текущей версии документа
     * 
     * @sa publishDiagnostics
    */
    virtual int document_version() const = 0;

    /**
     * @brief Нотификация об ошибках в тексте документа.
     * 
     * @details
     * LSP-сервер выполняет анализ текста при открытии и изменении документа. 
     * При этом каждый раз сервер отправляет клиенту нотификацию с диагностикой. 
     * Оболочка обрабатывает нотификацию и вызывает данный метод, чтобы плагин
     * мог отобразить диагностику.
     * 
     * LSP-сервер выполняет команды в параллельном режиме, поэтому ответ на 
     * какие-то команды может сильно задержаться. Для того, чтобы диагностика всегда 
     * соответствовала текущей версии документа, проверяйте значении параметра version, 
     * в котором передаётся версия документа, для которого пришла диагностика. Оболочка 
     * при открытии документа всегда начинает нумерацию с нуля.
     * 
     * @note Обратите внимание, что массив с диагностикой приходит в виде неконстантной
     * ссылки. Это значит, что его содержимое можно изменять, в том числе использовать
     * идиому swap для обмена старого содержимого вашего массива диагностики на новое.
     * 
     * @sa version
     * 
     * @param version Версия документа, для которой пришла диагностика
     * @param diagnostics Ссылка на массив с диагностикой
     * @param checksum Контрольная сумма диагностики (требуется для некоторых алгоритмов оптимизации)
    */
    virtual void publishDiagnostics(int version, QVector<shell::Diagnostic> & diagnostics, int checksum) = 0;

    /**
     * @brief Данный метод является откликом сервера на LSP-команду 'textDocument/hover'.
     * 
     * @details
     * Команда 'textDocument/hover' обычно используется для получения информации о символе 
     * под курсором мышки. Если значение параметра value пусто, то языковой 
     * сервер не смог определить символ под курсором или по другим причинам не может 
     * предоставить информацию.
     * 
     * @param sender Указатель на отправителя (необходим, если выполняется работа сразу с несколькими однотипными виджетами)
     * @param kind Формат полученной информации (текст 'plaintext' или 'markdown')
     * @param value Информация о символе под курсором
    */
    virtual void hover(const void * sender, const QString & kind, const QString & value) = 0;

    /**
     * @brief Данный метод является откликом сервера на LSP-команду 
     * 'textDocument/documentSymbol'.
     * 
     * @details
     * Команда 'textDocument/documentSymbol' обычно используется для получения некоторых
     * символов документа для отображения в аналоге QComboBox для быстрого перехода и для
     * информирования пользователя внутри какого символа находится курсор.
     * 
     * @note Обратите внимание, что массив с символами приходит в виде неконстантной
     * ссылки. Это значит, что его содержимое можно изменять, в том числе использовать
     * идиому swap для обмена старого содержимого вашего массива на новое.
     * 
     * @param symbols Массив с символами
    */
    virtual void documentSymbol(QVector<shell::DocumentSymbol> & symbols) = 0;

    /**
     * @brief Данный метод является откликом сервера на LSP-команду 
     * 'textDocument/semanticTokens'.
     * 
     * @details
     * Команда 'textDocument/semanticTokens' обычно используется для получения 
     * дополнительной информации о семантике символов (токенов) документа.
     * 
     * Оболочка формирует ответ сервера на эту команду в виде, удобном для быстрого 
     * построкового просмотра, либо для быстрого получения информации о токенах для
     * какой-то конкретной строки (по её номеру).
     * 
     * @note Обратите внимание, что контейнер с токенами приходит в виде неконстантной
     * ссылки. Это значит, что его содержимое можно изменять, в том числе использовать
     * идиому swap для обмена старого содержимого вашего контейнера на новое.
     * 
     * @param tokens Контейнер с токенами
     * @param checksum Контрольная сумма диагностики (требуется для некоторых алгоритмов оптимизации)
    */
    virtual void semanticTokens(std::multimap<int,shell::SemanticToken> & tokens, int checksum) = 0;

    /**
     * @brief Данный метод является откликом сервера на LSP-команду 
     * 'textDocument/completion'.
     * 
     * @details
     * Команда 'textDocument/completion' обычно используется для получения списка символов
     * для текущего контекста, чтобы подсказать пользователю редактора возможное продолжение.
     * 
     * @note Обратите внимание, что контейнер с символами приходит в виде неконстантной
     * ссылки. Это значит, что его содержимое можно изменять, в том числе использовать
     * идиому swap для обмена старого содержимого вашего контейнера на новое.
     * 
     * @param sender Указатель на отправителя (необходим, если выполняется работа сразу с несколькими однотипными виджетами)
     * @param tokens Контейнер с символами
    */
    virtual void completionItems(const void * sender, QVector<shell::CompletionItem> & completions) = 0;
};

}

#endif // simodo_shell_document_ViewAdaptorLsp_interface_H